﻿namespace IBTrader.Indicator.CandleStick
{
    using IBTrader.Modules.Read;
    using IBTrader.Charts;
    using System;
    using System.Linq;

    class ParabolicSAR : Base, IUpDown
    {
        private double ac, sar;
        private bool dir;
        private readonly Item[] items = new Item[2];
        public event EventHandler<Line> Up, Down;
        internal event EventHandler<Line> Buy, Sell, Point;
        public ParabolicSAR(Worker worker, int interval = 120) : base(worker, interval) { }
        protected override void Add(object sender, Item item)
        {
            items[0] = items[1];
            items[1] = item;

            if (items[0] != null)
            {
                var item1 = items[1];
                var item2 = items[0];

                if (ac == 0) // 1. initialize
                {
                    dir = item.Close > item1.Close;
                    ac = .02;
                    sar = dir ? Math.Min(item1.Low, item2.Low) : Math.Max(item1.High, item2.High);
                }
                else if (dir ? item.Typical > sar : item.Typical < sar) // 2. follow
                {
                    var m = dir ?
                        sar + ac * (item.High - sar) :
                        sar - ac * (item.Low + sar);
                    sar = dir ?
                        new[] { m, item.Low, item1.Low }.Min() :
                        new[] { m, item.High, item1.High }.Max();
                    if (dir ? item.High > item1.High : item.Low < item1.Low)
                        ac = Math.Min(.2, ac + .02);
                }
                else // 3. end and reset
                {
                    dir = !dir;
                    ac = .02;
                    sar = dir ? Math.Min(item1.Low, item2.Low) : Math.Max(item1.High, item2.High);
                    var hit = dir ? Buy : Sell;
                    if (hit != null) hit(sender, item.CloseLine);
                }

                if (sar != 0)
                {
                    OnHit(item.CloseLine, (float)sar);
                    var hit = dir ? Up : Down;
                    if (hit != null) hit(sender, NewLine(item.CloseLine, (float)sar));
                    if (!dir) OnHit(Point, ChartArgs.EventType.Point, item.CloseLine);
                }
            }
        }
    }
}